<template>
  <div
    ref="container"
    :style="containerStyle"
    :class="{ loaded: loaded }"
    class="progressive-bg"
  >
    <slot />
  </div>
</template>

<script lang="ts" setup>
import { ref, computed, onMounted, watch, defineProps } from "vue";

interface Props {
  src: string; // 高清图
  lowSrc?: string; // 低清图（可选）
  width?: string | number;
  height?: string | number;
  fit?: "cover" | "contain" | "fill" | "none" | "scale-down";
  position?: string; // background-position
  lazy?: boolean;
  fallback?: string;
}

const props = withDefaults(defineProps<Props>(), {
  fit: "cover",
  position: "center",
  lazy: true,
  width: "100%",
  height: "300px",
  fallback: ""
});

const container = ref<HTMLElement | null>(null);
const loaded = ref(false);
const observer = ref<IntersectionObserver | null>(null);

const containerStyle = computed(() => ({
  width: typeof props.width === "number" ? `${props.width}px` : props.width,
  height: typeof props.height === "number" ? `${props.height}px` : props.height,
  backgroundSize: props.fit,
  backgroundPosition: props.position,
  backgroundRepeat: "no-repeat",
  backgroundImage: props.lowSrc ? `url(${resolveSrc(props.lowSrc)})` : "none",
  transition: "filter 0.5s ease, transform 0.5s ease"
}));

function resolveSrc(src: string) {
  if (!src) return "";
  if (/^https?:\/\//.test(src)) return src;
  if (src.startsWith("@/")) {
    try {
      return new URL(src.replace(/^@/, "/src"), import.meta.url).href;
    } catch {
      console.warn("[ProgressiveBackground] 无法解析 @ 路径:", src);
    }
  }
  if (src.startsWith("./") || src.startsWith("../")) {
    try {
      return new URL(src, import.meta.url).href;
    } catch {
      console.warn("[ProgressiveBackground] 无法解析相对路径:", src);
    }
  }
  if (src.startsWith("/")) return src;
  return src;
}

function loadHighRes() {
  const el = container.value;
  if (!el) return;

  const img = new Image();
  img.src = resolveSrc(props.src);
  img.onload = () => {
    el.style.backgroundImage = `url(${img.src})`;
    loaded.value = true;
  };
  img.onerror = () => {
    if (props.fallback) {
      el.style.backgroundImage = `url(${resolveSrc(props.fallback)})`;
    }
    loaded.value = true;
  };
}

onMounted(() => {
  if (props.lazy && container.value) {
    observer.value = new IntersectionObserver(
      entries => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            loadHighRes();
            observer.value?.disconnect();
          }
        });
      },
      { threshold: 0.1 }
    );
    observer.value.observe(container.value);
  } else {
    loadHighRes();
  }
});
</script>

<style scoped>
.progressive-bg {
  position: relative;
  filter: blur(20px);
  transform: scale(1.05);
  overflow: hidden;
  transition:
    filter 0.5s ease,
    transform 0.5s ease;
}

.progressive-bg.loaded {
  filter: blur(0);
  transform: scale(1);
}
</style>
